#include <stdio.h>
#include <string.h>
#include <stdlib.h>


#define dmsg                    printf
#define dlog(fmt, arg...)       printf(fmt"\r\n", ##arg);

#define UINT8                   unsigned char
#define UINT16                  unsigned short
#define UINT32                  unsigned int

UINT32 width = 0;
UINT32 height = 0;

char input_name[16];
FILE *input_file = NULL;
UINT8 *input_buf = NULL;
UINT32 input_len = 0;

char output_name[16];
FILE *output_file = NULL;
UINT8 *output_buf = NULL;
UINT32 output_len = 0;

void rgb2yuv(UINT8 ir, UINT8 ig, UINT8 ib, UINT8 *oy, UINT8 *ou, UINT8 *ov)
{
    float r, g, b;
    float y, u, v;

    r = (float)ir;
    g = (float)ig;
    b = (float)ib;

#if 1
    /* CCIR 601 */
    /* RGB和YUV的范围都是[0,255] */
    y = 0.299 * r + 0.587 * g + 0.114 * b;
    u = -0.169 * r - 0.331 * g + 0.500 * b + 128;
    v = 0.500 * r - 0.419 * g - 0.081 * b + 128;
#else
    /* ISBN 1-878707-09-4 */
    /* RGB的范围是[0,255], Y的范围是[16,235], UV的范围是[16,239] */
    y = 0.257 * r + 0.504 * g + 0.098 * b + 16;
    u = -0.148 * r - 0.291 * g + 0.439 * b + 128;
    v = 0.439 * r - 0.368 * g - 0.071 * b + 128;
#endif

    /* float 类型强转为整形，做四舍五入转化的话，原本是要加 0.5 的 */
    /* 但是由于 FF 的颜色值，计算到的 YUV 分量的值为 255.5, 再加 0.5 后数据会溢出 */
    /* 因此这里迫不得已加 0.4999 将就一下 */
    *oy = (UINT8)(y + 0.4999);
    *ou = (UINT8)(u + 0.4999);
    *ov = (UINT8)(v + 0.4999);
}

void yuv2rgb(UINT8 iy, UINT8 iu, UINT8 iv, UINT8 *or, UINT8 *og, UINT8 *ob)
{
    float r, g, b;
    float y, u, v;

    y = (float)iy;
    u = (float)iu;
    v = (float)iv;

    r = y + 1.4075 * (v-128);
    g = y - 0.3455 * (u-128) - 0.7169*(v-128);
    b = y + 1.779 * (u-128);

    *or = (UINT8)(r + 0.4999);
    *og = (UINT8)(g + 0.4999);
    *ob = (UINT8)(b + 0.4999);
}

int main(int argc, char *argv[])
{
    UINT32 i = 0;
    UINT32 j = 0;
    UINT8 *p;
    UINT8 y, u, v;
    UINT8 r, g, b;

    //打印函数的使用方法
    //=============================================================
    if (argc != 5)
    {
        printf("usage: ./a.out xxx.nv12 xxx.aoutput width height\n");
        printf("eg   : ./a.out logo.nv12 logo.argb 320 240\n");
        printf("eg   : ./a.out logo.argb8888 logo.nv12new 320 240\n");
        printf("\n");
        return -1;
    }

    // 解析参数
    strcpy(input_name, argv[1]);
    strcpy(output_name, argv[2]);
    sscanf(argv[3], "%d", &width);
    sscanf(argv[4], "%d", &height);

    dlog("input_name    = %s", input_name);
    dlog("output_name   = %s", output_name);
    dlog("width         = %d", width);
    dlog("height        = %d", height);

    //申请内存, 按照最大内存申请
    //=============================================================
    input_len = width * height * 4;
    input_buf = (UINT8 *)malloc(input_len);
    memset(input_buf, 0, input_len);
    output_len = width * height * 4;
    output_buf = (UINT8 *)malloc(output_len);
    memset(output_buf, 0, output_len);

    //输入图片: 从文件中读取到内存中
    //=============================================================
    input_file = fopen(input_name, "rb");
    if (input_file == NULL)
    {
        printf("err: can not open %s file\n", input_name);
        return -1;
    }
    fread(input_buf, 1, input_len, input_file);
    fclose(input_file);
    dlog("read done");

    //颜色空间转化
    //=============================================================
    for(i = 0; i < width; i++)              // 列
    {
        for(j = 0; j < height; j++)         // 行
        {
#if 1
            p = input_buf + (j / 2) * width + (i / 2) * 2 + width * height;
            y = *(input_buf + j * width + i);
            u = *p;
            v = *(p + 1);

            yuv2rgb(y, u, v, &r, &g, &b);

            p = output_buf + j * width * 4 + i * 4;
            *p = 0xFF;
            *(p + 1) = r;
            *(p + 2) = g;
            *(p + 3) = b;
#else
            p = input_buf + j * width * 4 + i * 4;
            r = *(p + 1);
            g = *(p + 2);
            b = *(p + 3);

            rgb2yuv(r, g, b, &y, &u, &v);

            p = output_buf + j * width + i;
            *p = y;
            if ((i % 2 == 0) && (j % 2 == 0))
            {
                p = output_buf + width * height + (j / 2) * width + i;
                *p = v;
                *(p + 1) = u;
            }
#endif
        }
    }

    //输出图片: 从内存中写入到文件中
    //=============================================================
    output_file = fopen(output_name, "wb");
    if (output_file == NULL)
    {
        printf("err: can not open %s file\n", output_name);
        return -1;
    }

    fwrite(output_buf, 1, output_len, output_file);
    fclose(output_file);
    dlog("write done");

    //释放内存
    //=============================================================
    free(output_buf);
    free(input_buf);

    //测试颜色空间转化是否正确
    //=============================================================
    y = 76; // 红色
    u = 85;
    v = 255;
    yuv2rgb(y, u, v, &r, &g, &b);
    dlog("y/u/v ===> r/g/b: %d/%d/%d ===> %d/%d/%d", y, u, v, r, g, b);

    r = 76; // 红色
    g = 85;
    b = 255;
    yuv2rgb(y, u, v, &r, &g, &b);
    dlog("r/g/b ===> y/u/v: %d/%d/%d ===> %d/%d/%d", r, g, b, y, u, v);

    return 0;
}





























































